]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
layout: Reject promise if background loading is interrupted
authorFlorian Müllner <fmuellner@gnome.org>
Tue, 10 Feb 2026 14:30:46 +0000 (15:30 +0100)
committerMarge Bot <marge-bot@gnome.org>
Tue, 3 Mar 2026 12:49:04 +0000 (12:49 +0000)
Currently if a background manager is destroyed while we are waiting
for the background to load, the corresponding promise never resolves.

To prevent this from happening (and the startup animation getting
stuck as a result), guard the loading operation with a cancellable
and reject the promise when it is cancelled.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/9018
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/4070>

js/ui/layout.js

index 8f07ac63eb6f927be756925353de28452c509a2f..362598d3c966e9883a68a98d83bdd99b1864d5ca 100644 (file)
@@ -525,16 +525,25 @@ export const LayoutManager = GObject.registerClass({
         }
     }
 
-    _waitLoaded(bgManager) {
-        return new Promise(resolve => {
-            const id = bgManager.connect('loaded', () => {
-                bgManager.disconnect(id);
-                resolve();
-            });
+    _waitLoaded(bgManager, cancellable) {
+        const {promise, resolve, reject} = Promise.withResolvers();
+        const cancelId = cancellable.connect(() => {
+            reject(new GLib.Error(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
+                'Background loading was cancelled'));
+        });
+        const loadedId = bgManager.connect('loaded', () => {
+            bgManager.disconnect(loadedId);
+            cancellable.disconnect(cancelId);
+            resolve();
         });
+
+        return promise;
     }
 
     _updateBackgrounds() {
+        this._bgLoadCancellable?.cancel();
+        this._bgLoadCancellable = null;
+
         for (let i = 0; i < this._bgManagers.length; i++)
             this._bgManagers[i].destroy();
 
@@ -543,6 +552,9 @@ export const LayoutManager = GObject.registerClass({
         if (Main.sessionMode.isGreeter)
             return Promise.resolve();
 
+        const cancellable = new Gio.Cancellable();
+        this._bgLoadCancellable = cancellable;
+
         for (let i = 0; i < this.monitors.length; i++) {
             const bgManager = this._createBackgroundManager(i);
             this._bgManagers.push(bgManager);
@@ -551,7 +563,8 @@ export const LayoutManager = GObject.registerClass({
                 bgManager.backgroundActor.hide();
         }
 
-        return Promise.all(this._bgManagers.map(this._waitLoaded));
+        return Promise.all(
+            this._bgManagers.map(mgr => this._waitLoaded(mgr, cancellable)));
     }
 
     _updateKeyboardBox() {